import { Collapse, CollapsePanel } from '@components/Collapse';
import Cache from '../../types/cache.mdx';
import Columns from '@components/Columns';

# Cache

When writing Rspack plugins, you can use `compiler.getCache(name: string)` or `compilation.getCache(name: string)` to get the cache object which can share data in the build process. The cache data is stored on the `Compiler`, so it can be used in multiple `Compilation`s in the watch mode.

:::warning Notice

- Only available when [cache: true](/config/cache) which it is enabled in `mode="development"` by default.
- Only used for the JavaScript plugins, the Rust cache cannot be accessed.
- Only memory cache is provided, persistent cache is not supported yet.

:::

## Example

The following code finds out the newly added assets in the `processAssets`:

```js
compiler.hooks.compilation.tap('MyPlugin', compilation => {
  compilation.hooks.processAssets.tapPromise('MyPlugin', async () => {
    const cache = compilation.getCache('MyPlugin');
    const currentAssets = compilation.getAssets().map(i => i.name);
    const lastAssets = await cache.getPromise('assets', null);
    if (lastAssets) {
      for (const asset of currentAssets) {
        if (!lastAssets.includes(asset)) {
          console.log(`New asset: ${asset}`);
        }
      }
    }
    await cache.storePromise('assets', null, currentAssets);
  });
});
```

## Methods

### Caching

#### get/getPromise

Get cache data asynchronously, callback by function or promise.

- **Type:**
  - `get`: `<T>(identifier: string, etag: Etag | null, callback: (err: Error, result: T) => void): void`
  - `getPromise`: `<T>(identifier: string, etag: Etag | null): Promise<T>;`
- **Arguments:**
  - identifier: ID of data item
  - etag: Etag of the data item, can be generated by `getLazyHashedEtag`

#### store/storePromise

Store cache data asynchronously, callback by function or promise.

- **Type:**
  - `store`: `<T>(identifier: string, etag: Etag | null, data: T, callback: (err: Error) => void): void;`
  - `storePromise`: `<T>(identifier: string, etag: Etag | null): Promise<T>;`
- **Arguments:**
  - identifier: ID of data item
  - etag: Etag of the data item, can be generated by `getLazyHashedEtag`

#### provide/providePromise

Try to get cache data asynchronously, call the computer function to generate when not exists, callback by function or promise.

- **Type:**
  - `provide`:
    ```ts
    provide<T>(
      identifier: string,
      etag: Etag | null,
      computer: (fn: (err: Error, result: T) => void) => void,
      callback: () => T | Promise<T>,
    ): void;
    ```
  - `providePromise`
    ```ts
    providePromise<T>(
      identifier: string,
      etag: Etag | null,
      computer: () => T | Promise<T>,
    ): Promise<T>;
    ```
- **Arguments:**
  - identifier: ID of data item
  - etag: Etag of the data item, can be generated by `getLazyHashedEtag`
  - computer: The called generating function when cache is not exists

<Columns>

```js title=MyPlugin.js
const createAssetsData = async () => {
  console.log('only called once');
  return compilation.getAssets().map(i => i.name);
};

compilation.hooks.processAssets.tapPromise('MyPlugin', async () => {
  const cache = compilation.getCache('MyPlugin');
  console.log(await cache.getPromise('assets', null)); // undefined
  await cache.providePromise('assets', null, createAssetsData); // call createAssetsData
  console.log(await cache.getPromise('assets', null)); // ["main.js"]
  await cache.providePromise('assets', null, createAssetsData); // not call
});
```

```txt title=Output
undefined
only called once
[ 'main.js' ]
```

</Columns>

### getLazyHashedEtag/mergeEtags

By using the `getLazyHashedEtag` and `mergeEtags` methods, an etag can be created as the unique identifier of the data item. It will not be calculated immediately when created, but rather delayed until it is used, and also can be cached. This can be used to improve performance when complex data objects are used as the unique identifier.

- `getLazyHashedEtag`: `(obj: HashableObject): Etag`, calculates the hash of the object to generate the etag as the data identifier, the object needs to implement the `updateHash(hash: Hash)`.
- `mergeEtags`: `(a: Etag, b: Etag): Etag`, merges two etags to one.

<Columns>
```js title=MyPlugin.js
const cache = compilation.getCache('MyPlugin');
const dataEtag = cache.getLazyHashedEtag({
  content: 'a'.repeat(10000),
  updateHash(hash) {
    console.log("only called once");
    hash.update(this.content);
  }
});
const mergedEtag = cache.mergeEtags(dataEtag, "other etag");
await cache.storePromise("assets", mergedEtag, "cached value");
console.log(await cache.getPromise("assets", mergedEtag));
```

```txt title=Output
only called once
cached value
```

</Columns>

### getItemCache

By using the `getItemCache` method, a cache object for a single data item can be created. This cache object provides simplified data access methods, do not need identifier and etag as arguments any more.

- **Type:** `(identifier, etag): ItemCacheFacade`

```ts
type ItemCacheFacade = {
  get<T>(callback: (err: Error, result: T) => void): void; // async data getter, callback by function
  getPromise<T>(): Promise<T>; // async data getter, callback by promise
  store<T>(data: T, callback: (err: Error, result: T) => void): void; // async data setter, callback by function
  storePromise<T>(data: T): Promise<void>; // async data setter, callback by promise
  provide<T>( // try to get the data, use function to compute if not exists, callback by function
    computer: (fn: (err: Error, result: T) => void) => void,
    callback: (err: Error, result: T) => void,
  ): void;
  providePromise<T>( // try to get the data, use function to compute if not exists, callback by promise
    computer: (fn: (err: Error, result: T) => void) => void,
  ): Promise<T>;
};
```

<Columns>

```js title=MyPlugin.js
const cache = compilation.getCache('MyPlugin');
const itemCache = cache.getItemCache('item');
await itemCache.storePromise('cached value');
console.log(await itemCache.getPromise());
```

```txt title=Output
cached value
```

</Columns>

### getChildCache

By using the `getChildCache` method, a child cache object can be generated, with its interface being completely consistent, and it can be utilized when there are numerous caches that require grouping for storage.

- **Type:** `(name: string): CacheFacade`
